home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / SOURCES / STRBROWS.C < prev    next >
C/C++ Source or Header  |  1992-02-26  |  17KB  |  675 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * StringBrowser implementation.
  25.  */
  26.  
  27. #include <InterViews/bitmap.h>
  28. #include <InterViews/button.h>
  29. #include <InterViews/cursor.h>
  30. #include <InterViews/font.h>
  31. #include <InterViews/painter.h>
  32. #include <InterViews/perspective.h>
  33. #include <InterViews/sensor.h>
  34. #include <InterViews/shape.h>
  35. #include <InterViews/strbrowser.h>
  36. #include <InterViews/textdisplay.h>
  37.  
  38. #include <InterViews/Bitmaps/hand.bm>
  39. #include <InterViews/Bitmaps/handm.bm>
  40. #include <InterViews/Bitmaps/dfast.bm>
  41. #include <InterViews/Bitmaps/dfastm.bm>
  42. #include <InterViews/Bitmaps/ufast.bm>
  43. #include <InterViews/Bitmaps/ufastm.bm>
  44.  
  45. #include <math.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48.  
  49. StringBrowser::StringBrowser (
  50.     ButtonState* bs, int r, int c, boolean u, int h, const char* d
  51. ) {
  52.     Init(bs, r, c, u, h, d);
  53. }
  54.  
  55. StringBrowser::StringBrowser (
  56.     const char* name,
  57.     ButtonState* bs, int r, int c, boolean u, int h, const char* d
  58. ) {
  59.     SetInstance(name);
  60.     Init(bs, r, c, u, h, d);
  61. }
  62.  
  63. void StringBrowser::Init (
  64.     ButtonState* bs, int r, int c, boolean u, int h, const char* d
  65. ) {
  66.     const int defaultSize = 256;
  67.  
  68.     SetClassName("StringBrowser");
  69.     input = new Sensor;
  70.     input->Reference();
  71.     input->Catch(DownEvent);
  72.     input->Catch(KeyEvent);
  73.  
  74.     strbufsize = selbufsize = defaultSize;
  75.     strbuf = new char*[strbufsize];
  76.     selbuf = new char*[selbufsize];
  77.     strcount = selcount = 0;
  78.  
  79.     display = nil;
  80.     rows = r;
  81.     columns = c;
  82.     uniqueSel = u;
  83.     singleClick = false;
  84.     highlight = h;
  85.     lastx = lasty = -1;
  86.     subject = bs;
  87.     done = d;
  88.     perspective = new Perspective;
  89.     firstResize = true;
  90.     InitTextDisplay();
  91. }
  92.  
  93. void StringBrowser::InitTextDisplay () {
  94.     delete display;
  95.     display = new TextDisplay;
  96.     display->CaretStyle(NoCaret);
  97.  
  98.     for (int i = 0; i < strcount; ++i) {
  99.         display->ReplaceText(i, strbuf[i], strlen(strbuf[i]));
  100.     }
  101.     if (canvas != nil) {
  102.         output->ClearRect(canvas, 0, 0, xmax, ymax);
  103.         firstResize = true;
  104.         Resize();
  105.     }
  106. }
  107.  
  108. StringBrowser::~StringBrowser () {
  109.     Clear();
  110.     delete strbuf;
  111.     delete display;
  112.     Unref(perspective);
  113. }
  114.  
  115. static void BufCheck (char**& buf, int& bufsize, int count, int index) {
  116.     char** newbuf;
  117.  
  118.     if (index >= bufsize) {
  119.     bufsize = (index+1) * 2;
  120.     newbuf = new char*[bufsize];
  121.     memmove(newbuf, buf, count*sizeof(char*));
  122.     delete buf;
  123.     buf = newbuf;
  124.     }
  125. }
  126.  
  127. static void BufInsert (
  128.     char* s, int index, char**& buf, int& bufsize, int& count
  129. ) {
  130.     char** spot;
  131.     index = (index < 0) ? count : index;
  132.  
  133.     if (index < count) {
  134.     BufCheck(buf, bufsize, count, count+1);
  135.     spot = &buf[index];
  136.     memmove(spot+1, spot, (count - index)*sizeof(char*));
  137.  
  138.     } else {
  139.     BufCheck(buf, bufsize, count, index);
  140.     spot = &buf[index];
  141.     }
  142.     *spot = s;
  143.     ++count;
  144. }
  145.  
  146. static void BufRemove (int index, char** buf, int& count) {
  147.     if (index < --count) {
  148.     char** spot = &buf[index];
  149.     memmove(spot, spot+1, (count - index)*sizeof(char*));
  150.     }
  151. }
  152.  
  153. static int BufFind (
  154.     int index,
  155.     char** srcbuf, int srccount,
  156.     char** dstbuf, int dstcount
  157. ) {
  158.     if (0 <= index && index < srccount) {
  159.     char* s = srcbuf[index];
  160.  
  161.     if (s != nil) {
  162.         for (int i = 0; i < dstcount; ++i) {
  163.         if (dstbuf[i] == s) {
  164.             return i;
  165.         }
  166.         }
  167.     }
  168.     }
  169.     return -1;
  170. }
  171.  
  172. void StringBrowser::Insert (const char* s, int index) {
  173.     register Perspective* p = perspective;
  174.  
  175.     char* copy = new char[strlen(s)+1];
  176.     strcpy(copy, s);
  177.     BufInsert(copy, index, strbuf, strbufsize, strcount);
  178.  
  179.     p->height += lineheight;
  180.     p->cury += lineheight;
  181.     p->Update();
  182.     if (index < strcount-1) {
  183.     display->InsertLinesAfter(index-1, 1);
  184.     }
  185.     display->ReplaceText(index, s, strlen(s));
  186. }
  187.  
  188. void StringBrowser::Remove (int index) {
  189.     if (0 <= index && index < strcount) {
  190.     register Perspective* p = perspective;
  191.  
  192.     Unselect(index);
  193.     BufRemove(index, strbuf, strcount);
  194.     delete String(index);
  195.  
  196.     p->height -= lineheight;
  197.     p->cury -= lineheight;
  198.     p->Update();
  199.     display->DeleteLinesAfter(index-1, 1);
  200.     }
  201. }
  202.  
  203. int StringBrowser::Index (const char* s) {
  204.     for (int i = 0; i < strcount; ++i) {
  205.     if (strcmp(s, strbuf[i]) == 0) {
  206.         return i;
  207.     }
  208.     }
  209.     return -1;
  210. }
  211.  
  212. char* StringBrowser::String (int index) {
  213.     return (0 <= index && index < strcount) ? strbuf[index] : nil;
  214. }
  215.  
  216. void StringBrowser::Clear () {
  217.     for (int i = 0; i < strcount; ++i) {
  218.     delete strbuf[i];
  219.     }
  220.     strcount = selcount = 0;
  221.     InitTextDisplay();
  222. }
  223.  
  224. void StringBrowser::Select (int index) {
  225.     if (index < strcount && !Selected(index)) {
  226.     BufInsert(String(index), selcount, selbuf, selbufsize, selcount);
  227.     display->Style(index, 0, index, columns, highlight);
  228.     }
  229. }
  230.  
  231. void StringBrowser::Unselect (int index) {
  232.     int selindex;
  233.  
  234.     if (index < strcount && (selindex = SelectionIndex(index)) >= 0) {
  235.     BufRemove(selindex, selbuf, selcount);
  236.     display->Style(index, 0, index, columns, Plain);
  237.     }
  238. }
  239.  
  240. int StringBrowser::Selection (int selindex) {
  241.     return BufFind(selindex, selbuf, selcount, strbuf, strcount);
  242. }
  243.  
  244. int StringBrowser::SelectionIndex (int index) {
  245.     return BufFind(index, strbuf, strcount, selbuf, selcount);
  246. }
  247.  
  248. void StringBrowser::Browse () {
  249.     Event e;
  250.     e.target = nil;
  251.     e.eventType = EnterEvent;
  252.     Handle(e);
  253. }
  254.  
  255. boolean StringBrowser::HandleDownEvent (Event& e) {
  256.     boolean done = true;
  257.  
  258.     if (e.target == this) {
  259.         if (e.button == LEFTMOUSE) {
  260.             done = LeftButtonDown(e);
  261.         } else if (e.button == MIDDLEMOUSE) {
  262.             GrabScroll(e);
  263.     } else if (e.button == RIGHTMOUSE) {
  264.             RateScroll(e);
  265.         }
  266.     } else {
  267.         UnRead(e);
  268.     }
  269.     return done;
  270. }
  271.  
  272. boolean StringBrowser::HandleKeyEvent (Event& e) {
  273.     boolean done = false;
  274.  
  275.     if (e.len != 0) {
  276.         done = HandleChar(e.keystring[0]);
  277.     }
  278.     return done;
  279. }    
  280.  
  281. void StringBrowser::Handle (Event& e) {
  282.     if (e.eventType == KeyEvent) {
  283.         HandleKeyEvent(e);
  284.  
  285.     } else {
  286.         boolean done = false;
  287.  
  288.         do {
  289.             switch (e.eventType) {
  290.         case DownEvent:
  291.                 done = HandleDownEvent(e);
  292.                 break;
  293.  
  294.             case KeyEvent:
  295.                 done = HandleKeyEvent(e);
  296.                 break;
  297.             }
  298.             if (!done) {
  299.         Read(e);
  300.             }
  301.         } while (!done);
  302.     }
  303. }
  304.  
  305. boolean StringBrowser::HandleChar (char c) {
  306.     int index = Selection();
  307.  
  308.     switch (c) {
  309.     case SBFirstString:
  310.         ScrollTo(0);
  311.         break;
  312.     case SBLastString:
  313.         ScrollTo(strcount-1);
  314.         break;
  315.     case SBScrollDown:
  316.         ScrollBy(1);
  317.     break;
  318.     case SBScrollUp:
  319.         ScrollBy(-1);
  320.         break;
  321.     case SBSelectAll:
  322.         if (!uniqueSel) {
  323.             SelectAll();
  324.         }
  325.         break;
  326.     case SBUnselectAll:
  327.     case SBUnselectAllAlt:
  328.         UnselectAll();
  329.         break;
  330.     case SBSelectPreviousString:
  331.         Unselect(index);
  332.         index = max(0, min(--index, strcount-1));
  333.         Select(index);
  334.         ScrollTo(index);
  335.     break;
  336.     case SBSelectNextString:
  337.         Unselect(index);
  338.         index = max(0, min(++index, strcount-1));
  339.         Select(index);
  340.         ScrollTo(index);
  341.         break;
  342.     case SBSelectTopString:
  343.         Unselect(index);
  344.     index = Locate(0, ymax);
  345.         Select(index);
  346.         break;
  347.     case SBSelectBottomString:
  348.         Unselect(index);
  349.         index = Locate(0, 0);
  350.         Select(index);
  351.         break;
  352.     case SBPageDown:
  353.     ScrollBy((ymax+1) / lineheight);
  354.         break;
  355.     case SBPageUp:
  356.         ScrollBy(-(ymax+1) / lineheight);
  357.         break;
  358.     case SBHalfPageDown:
  359.         ScrollBy((ymax+1) / lineheight / 2);
  360.         break;
  361.     case SBHalfPageUp:
  362.     ScrollBy(-(ymax+1) / lineheight / 2);
  363.         break;
  364.     default:
  365.         for (int i = 0; done[i] != '\0'; ++i) {
  366.             if (c == done[i]) {
  367.                 subject->SetValue(c);
  368.                 return true;
  369.             }
  370.         }
  371.     break;
  372.     }
  373.     return false;
  374. }
  375.  
  376. void StringBrowser::Adjust (Perspective& np) {
  377.     register Perspective* p = perspective;
  378.     float scale = float(np.height) / float(p->height);
  379.     ScrollTo(0, p->y0 + int((np.cury - np.y0) / scale));
  380. }
  381.  
  382. static Cursor* handCursor;
  383. static Cursor* upCursor;
  384. static Cursor* dnCursor;
  385.  
  386. void StringBrowser::Reconfig () {
  387.     if (handCursor == nil) {
  388.         Bitmap hand(
  389.         hand_bits, hand_width, hand_height, hand_x_hot, hand_y_hot
  390.         );
  391.         Bitmap handmask(hand_mask_bits, hand_mask_width, hand_mask_height);
  392.         Bitmap up(
  393.             ufast_bits, ufast_width, ufast_height, ufast_x_hot, ufast_y_hot
  394.         );
  395.         Bitmap upmask(ufast_mask_bits, ufast_mask_width, ufast_mask_height);
  396.         Bitmap dn(
  397.             dfast_bits, dfast_width, dfast_height, dfast_x_hot, dfast_y_hot
  398.     );
  399.         Bitmap dnmask(dfast_mask_bits, dfast_mask_width, dfast_mask_height);
  400.  
  401.         handCursor = new Cursor(
  402.             &hand, &handmask, output->GetFgColor(), output->GetBgColor()
  403.         );
  404.         upCursor = new Cursor(
  405.             &up, &upmask, output->GetFgColor(), output->GetBgColor()
  406.         );
  407.     dnCursor = new Cursor(
  408.             &dn, &dnmask, output->GetFgColor(), output->GetBgColor()
  409.         );
  410.     }
  411.  
  412.     Font* f = output->GetFont();
  413.     shape->hunits = f->Width("n");
  414.     shape->vunits = f->Height();
  415.     lineheight = shape->vunits;
  416.     shape->Rect(shape->hunits*columns, shape->vunits*rows);
  417.     shape->Rigid(hfil, hfil, shape->height - lineheight, vfil);
  418.  
  419.     const char* attrib = GetAttribute("singleClick");
  420.     singleClick = (attrib != nil && strcmp(attrib, "on") == 0);
  421.  
  422.     attrib = GetAttribute("clickDelay");
  423.     clickDelay = (attrib == nil) ? 250 : atoi(attrib);
  424. }
  425.  
  426. void StringBrowser::Resize () {
  427.     register Perspective* p = perspective;
  428.  
  429.     p->sx = shape->hunits;
  430.     p->sy = lineheight;
  431.     p->lx = xmax+1;
  432.     p->ly = ymax+1;
  433.     p->width = columns * shape->hunits;
  434.     p->height = Count() * lineheight;
  435.     p->curwidth = xmax+1;
  436.     p->curheight = ymax+1;
  437.  
  438.     if (firstResize) {
  439.         p->curx = 0;
  440.         p->cury = p->height - p->curheight;
  441.         firstResize = false;
  442.     }
  443.     p->Update();
  444.     display->Draw(output, canvas);
  445.     display->LineHeight(lineheight);
  446.  
  447. /*
  448.  *   Originalversion:
  449.  *
  450.  *   display->Resize(0, -lineheight, xmax, ymax);
  451.  */
  452.  
  453.      display->Resize(0, 0, xmax, ymax);
  454. }
  455.  
  456. void StringBrowser::Redraw (Coord l, Coord b, Coord r, Coord t) {
  457.     display->Redraw(l, b, r, t);
  458. }
  459.  
  460. void StringBrowser::Select (int dot, int mark) {
  461.     for (int i = min(dot, mark); i <= max(dot, mark); ++i) {
  462.         Select(i);
  463.     }
  464. }
  465.  
  466. void StringBrowser::SelectAll () {
  467.     for (int i = 0; i < strcount; ++i) {
  468.     BufInsert(strbuf[i], selcount, selbuf, selbufsize, selcount);
  469.     }
  470.     display->Style(0, 0, strcount, 0, highlight);
  471. }
  472.  
  473. void StringBrowser::Unselect (int dot, int mark) {
  474.     for (int i = min(dot, mark); i <= max(dot, mark); ++i) {
  475.         Unselect(i);
  476.     }
  477. }
  478.  
  479. void StringBrowser::UnselectAll () {
  480.     selcount = 0;
  481.     display->Style(0, 0, strcount, 0, Plain);
  482. }
  483.  
  484. void StringBrowser::ScrollBy (int, int dy) {
  485.     ScrollTo(0, perspective->cury + dy);
  486. }
  487.  
  488. void StringBrowser::ScrollBy (int lines) {
  489.     ScrollBy(0, -lines*lineheight);
  490. }
  491.  
  492. void StringBrowser::ScrollTo (int x, int y) {
  493.     register Perspective* p = perspective;
  494.     int maxy = p->height - p->curheight;
  495.     int miny = min(maxy, 1-lineheight);
  496.  
  497.     p->cury = max(miny, min(y, maxy));
  498.     p->Update();
  499.     int topmargin = p->height - p->curheight - p->cury;
  500.     int line = topmargin / lineheight;
  501.     display->Scroll(line, x, ymax);
  502. }
  503.  
  504. void StringBrowser::ScrollTo (int index) {
  505.     register Perspective* p = perspective;
  506.     Coord y0 = p->y0 + p->cury;
  507.     Coord y = p->height - (index+1)*lineheight - y0;
  508.  
  509.     if (y > ymax) {
  510.         ScrollTo(0, y0 - (ymax-y));
  511.     } else if (y < 0) {
  512.         y -= (p->curheight % lineheight == 0) ? 0 : lineheight;
  513.     ScrollTo(0, y0 - (-y));
  514.     }
  515. }
  516.  
  517. void StringBrowser::ScrollToView (Coord, Coord y) {
  518.     register Perspective* p = perspective;
  519.  
  520.     if (y > ymax) {
  521.         ScrollTo(0, p->y0 + p->cury - (ymax-y));
  522.     } else if (y < 0) {
  523.         ScrollTo(0, p->y0 + p->cury - (-y));
  524.     }
  525. }
  526.  
  527. int StringBrowser::Locate (Coord, Coord y) {
  528.     register Perspective* p = perspective;
  529.  
  530.     y = max(p->curheight % lineheight, min(y, p->curheight-1));
  531.     return display->LineNumber(y);
  532. }
  533.  
  534. void StringBrowser::Note (Event& e) {
  535.     lasttime = e.timestamp;
  536.     lastx = e.x;
  537.     lasty = e.y;
  538. }
  539.  
  540. boolean StringBrowser::DoubleClicked (Event& e) {
  541.     if (e.eventType != DownEvent) {
  542.     return false;
  543.     }
  544.     const int distThresh = 4;
  545.     int time = abs(int(e.timestamp - lasttime));
  546.     int dist = abs(e.x - lastx) + abs(e.y - lasty);
  547.  
  548.     return time < clickDelay && dist < distThresh;
  549. }
  550.  
  551. void StringBrowser::UpdateSelection (int d, int m, int style) {
  552.     int oldl = min(lastdot, lastmark);
  553.     int oldr = max(lastdot, lastmark);
  554.     int newl = min(d, m);
  555.     int newr = max(d, m);
  556.  
  557.     if (newr < oldl || newl > oldr) {           // no overlap
  558.     if (style == highlight) {
  559.             Unselect(oldl, oldr);
  560.         }
  561.         if (style == highlight) {
  562.             Select(newl, newr);
  563.         } else {
  564.             Unselect(newl, newr);
  565.         }
  566.     } else {                                    // overlap
  567.     if (newl < oldl) {
  568.             if (style == highlight) {
  569.                 Select(newl, oldl);
  570.             } else {
  571.                 Unselect(newl, oldl);
  572.             }
  573.         } else if (newl > oldl) {
  574.             if (style == highlight) {
  575.                 Unselect(oldl, newl-1);
  576.         }
  577.         }
  578.         if (newr > oldr) {
  579.             if (style == highlight) {
  580.                 Select(oldr, newr);
  581.             } else {
  582.                 Unselect(oldr, newr);
  583.             }
  584.         } else if (newr < oldr) {
  585.         if (style == highlight) {
  586.                 Unselect(newr+1, oldr);
  587.             }
  588.         }
  589.     }
  590.     lastdot = d;
  591.     lastmark = m;
  592. }
  593.  
  594. boolean StringBrowser::LeftButtonDown (Event& e) {
  595.     boolean status = false;
  596.  
  597.     if (DoubleClicked(e)) {
  598.         subject->SetValue(done[0]);
  599.         status = true;
  600.  
  601.     } else if (uniqueSel) {
  602.         if (Selections() == 0) {
  603.         Select(Locate(e.x, e.y));
  604.         } else {
  605.             Unselect(Selection());
  606.             if (!e.shift) {
  607.                 Select(Locate(e.x, e.y));
  608.             }
  609.         }
  610.  
  611.     } else {
  612.     lastdot = lastmark = Locate(e.x, e.y);
  613.  
  614.         if (Selected(lastdot) && e.shift) {
  615.             Unselect(lastdot);
  616.             do {
  617.                 ScrollToView(e.x, e.y);
  618.                 UpdateSelection(lastdot, Locate(e.x, e.y), Plain);
  619.                 Poll(e);
  620.             } while (e.leftmouse);
  621.  
  622.         } else {
  623.             if (!e.shift) {
  624.                 UnselectAll();
  625.             }
  626.             Select(lastdot);
  627.             do {
  628.                 ScrollToView(e.x, e.y);
  629.                 UpdateSelection(lastdot, Locate(e.x, e.y), highlight);
  630.         Poll(e);
  631.             } while (e.leftmouse);
  632.         }
  633.     }
  634.     Note(e);
  635.     if (singleClick) {
  636.         subject->SetValue(done[0]);
  637.         status = true;
  638.     }
  639.     return status;
  640. }
  641.  
  642. void StringBrowser::GrabScroll (Event& e) {
  643.     int y = e.y;
  644.     int x = e.x;
  645.     Cursor* origCursor = GetCursor();
  646.     SetCursor(handCursor);
  647.  
  648.     do {
  649.         ScrollBy(x - e.x, y - e.y);
  650.         y = e.y;
  651.         x = e.x;
  652.         Poll(e);
  653.     } while (e.middlemouse);
  654.  
  655.     SetCursor(origCursor);
  656. }
  657.  
  658. void StringBrowser::RateScroll (Event& e) {
  659.     Cursor* origCursor = GetCursor();
  660.     int y = e.y;
  661.     int x = e.x;
  662.  
  663.     do {
  664.         ScrollBy(e.x - x, e.y - y);
  665.         if (e.y - y < 0) {
  666.         SetCursor(dnCursor);
  667.         } else {
  668.             SetCursor(upCursor);
  669.         }
  670.         Poll(e);
  671.     } while (e.rightmouse);
  672.  
  673.     SetCursor(origCursor);
  674. }
  675.